/*
Copyright (C) 2021-2025 Casa Xu (also Zhiyan Xu) from HIT

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*
 * LOS_FATFS.c
 *
 *  Created on: 2022年7月28日
 *      Author: 64435
 */

#include "LOS_FATFS.h"
#include "ff.h"
#include "diskio.h"


FATFS fs;
uint8_t readbuf[128];
uint8_t work[FF_MAX_SS];
FIL wfile;
FIL rfile;
FIL rfile_task;  //遥控任务队列专用
FILINFO fileinfo;
DIR dir;



/** @fn uint8_t LOS_FATFS_Init()
*   @brief FATFS文件系统初始化
*   @return 0-初始化成功  其他值-初始化失败
*/
uint8_t LOS_FATFS_Init()
{
    uint8_t res_sd = 0;
    

    disk_initialize(1);
    LOS_WDT_Feed();
    res_sd = f_mount(&fs, "1:", 1);

    if (res_sd == FR_NO_FILESYSTEM)
    {
        res_sd = f_mkfs("1:", 0, work, 512);

        if (res_sd == FR_OK)
        {
            res_sd = f_mount(NULL, "1:", 1);
            res_sd = f_mount(&fs, "1:", 1);
        }
        else
        {
            return 1;
        }
    }
    else if (res_sd != FR_OK)
    {
        return 2;
    }
    else
    {
        return 0;
    }
}


/** @fn uint8_t LOS_FATFS_WriteEOF(uint8_t* path, uint8_t* data, uint32_t length)
*   @brief FATFS写文件（从文件末尾开始）
*   @param[in] path 文件路径: 格式示例："1:a.txt"
*   @param[in] data 指向待写入数据的指针
*   @param[in] length 写入数据长度
*   @return 该函数的返回值为:
*           - 0: 写入成功   
*           - 其他值: 写入失败
*/
uint8_t LOS_FATFS_WriteEOF(uint8_t* path, uint8_t* data, uint32_t length)
{
    uint32_t bhw = 0;
    FRESULT res_sd; 

    res_sd = f_open(&wfile, path, FA_OPEN_APPEND | FA_WRITE);
    if (res_sd == FR_OK)
    {
        res_sd = f_write(&wfile, data, length, &bhw);
        if (res_sd == FR_OK)
        {
            f_close(&wfile);
            return res_sd;
        }
        else
        {
            f_close(&wfile);
            return res_sd;
        }

    }
    else
    { 
        f_close(&wfile);
        return res_sd;
    }
}

/** @fn uint8_t LOS_FATFS_Write(uint8_t* path, uint8_t* data, uint32_t length, uint32_t offset)
*   @brief FATFS写文件（写入到指定偏移地址）
*   @param[in] path 文件路径: 格式示例："1:a.txt"
*   @param[in] data 指向待写入数据的指针
*   @param[in] length 写入数据长度
*   @param[in] offset 偏移地址
*   @param[in] size 被写入文件当前的大小
*   @return 该函数的返回值为:
*           - 0: 写入成功   
*           - 其他值: 写入失败
*/
uint8_t LOS_FATFS_Write(uint8_t* path, uint8_t* data, uint32_t length, uint32_t offset, uint32_t* size)
{
    uint32_t bhw = 0;
    FRESULT res_sd; 
    uint8_t errcnt = 0;
    do
    {
        res_sd = f_open(&wfile, path, FA_OPEN_ALWAYS | FA_WRITE);
        errcnt++;
    }while(res_sd!=FR_OK && (errcnt < 30));
    errcnt = 0;
    if (res_sd == FR_OK)
    {
        do
        {
            res_sd = f_lseek(&wfile, offset); //移动指针至指定偏移地址
            errcnt++;
        } while (res_sd!=FR_OK && (errcnt < 30));
        errcnt = 0;
        if(res_sd == FR_OK)
        {
            do
            {
                res_sd = f_write(&wfile, data, length, &bhw);
                errcnt++;
            } while (res_sd!=FR_OK && (errcnt < 30));
            errcnt = 0;
            if (res_sd == FR_OK)
            {
                *size = f_size(&wfile);
                f_close(&wfile);
                return res_sd;
            }
            else
            {
                f_close(&wfile);
                return res_sd;
            }
        }
        else
        {
            f_close(&wfile);
            return res_sd;
        }
    }
    else
    { 
        f_close(&wfile);
        return res_sd;
    }
}

/** @fn uint8_t LOS_FAFTS_DeleteFile(uint8_t* path)
*   @brief FATFS删除文件
*   @param[in] path 文件路径: 格式示例："1:a.txt"
*   @return 该函数的返回值为:
*           - 0: 删除成功   
*           - 其他值: 写入失败
*   @note 
*/
uint8_t LOS_FAFTS_DeleteFile(uint8_t* path)
{
    return f_unlink(path);
}


/** @fn uint8_t LOS_FATFS_ScanDir(uint8_t* path)
*   @brief FATFS扫描目录下的所有文件
*   @param[in] path 文件路径: 格式示例："1:"
*   @return 该函数的返回值为:
*           - 0: 扫描成功   
*           - 其他值: 扫描失败
*   @note 该函数会将扫描到的文件名通过CAN总线发送出来
*/
uint8_t LOS_FATFS_ScanDir(uint8_t* path)
{
    FRESULT res;	 
    res = f_opendir(&dir,(const TCHAR*)path); 
    if (res == FR_OK) 
	{	
		while(1)
		{
	        res = f_readdir(&dir, &fileinfo);                  
	        if (res != FR_OK || fileinfo.fname[0] == 0) 
            {
                break;
            }  
            LOS_CAN_Transmit(LOS_CAN_NUM1, 0x08000001, fileinfo.fname, 8);
		} 
    }	   
    return res;	 
}


/** @fn uint8_t LOS_FATFS_ClearFile(uint8_t* path)
*   @brief FATFS清空指定文件内容
*   @param[in] path 文件路径: 格式示例："1:"
*   @return 该函数的返回值为:
*           - 0: 清空成功   
*           - 其他值: 清空失败
*   @note 该函数会将指定文件内容清空，但不删除文件
*/
uint8_t LOS_FATFS_ClearFile(uint8_t* path)
{
    FRESULT res_sd; 

    res_sd = f_open(&wfile, path, FA_OPEN_ALWAYS | FA_WRITE);
    if (res_sd == FR_OK)
    {
        f_lseek(&wfile, 0);
        f_truncate(&wfile);
        if (res_sd == FR_OK)
        {
            f_close(&wfile);
            return res_sd;
        }
        else
        {
            f_close(&wfile);
            return res_sd;
        }

    }
    else
    {
        f_close(&wfile);
        return res_sd;
    }
}


/** @fn uint32_t LOS_FATFS_Size(uint8_t* filename)
*   @brief FATFS获取文件大小
*   @param[in] filename   - 文件路径，示例："1:upd.bin"
*   @return uint32_t文件大小，若为0则错误
*   @note 
*/
uint32_t LOS_FATFS_Size(uint8_t* filename)
{
    uint8_t res_sd = 0;
    static uint32_t bhr = 0;
    uint32_t size = 0;

    res_sd = f_open(&rfile, filename, FA_OPEN_EXISTING | FA_READ);
    if (res_sd == FR_OK)
    {
        size = f_size(&rfile);
        f_close(&rfile);
        return size;
    }
    else
    {
        f_close(&rfile);
        return 0;
    }
}




/****************************************************测试函数***************************************************************/




uint8_t LOS_FATFS_TestWrite(uint8_t fn)
{
    
    static uint32_t bhw = 0;
    uint8_t res_sd = 0;
    uint8_t wbuf[30];
    uint8_t cnt = 0;
    uint8_t filename[9]="1:a1.txt";

    filename[2] = fn;


    for (cnt=0; cnt<30; cnt++)
    {
        wbuf[cnt] = cnt + 65;
    }

    
    res_sd = f_open(&wfile, filename, FA_CREATE_ALWAYS | FA_WRITE);
    if (res_sd == FR_OK)
    {
        res_sd = f_write(&wfile, wbuf, 30, &bhw);
        if (res_sd == FR_OK)
        {
            f_close(&wfile);
            return 0;
        }
        else
        {
            f_close(&wfile);
            return 1;
        }

    }
    else
    {
        f_close(&wfile);
        return 2;
    }

}


uint8_t LOS_FATFS_TestRead(uint8_t fn)
{
 
    uint8_t res_sd = 0;
    static uint32_t bhr = 0;
    uint8_t filename[10]="1:upd.bin";

    //filename[2] = fn;


    res_sd = f_open(&rfile, filename, FA_OPEN_EXISTING | FA_READ);
    if (res_sd == FR_OK)
    {
        res_sd = f_read(&rfile, readbuf, 128, &bhr);
        if (res_sd == FR_OK)
        {
            f_close(&rfile);
            return 0;
        }
        else
        {
            f_close(&rfile);
            return 1;
        }
    }
    else
    {
        f_close(&rfile);
        return 2;
    }

}


uint8_t LOS_FATFS_TestScan(uint8_t* path)
{
    FRESULT res;	 
    res = f_opendir(&dir,(const TCHAR*)path); 
    if (res == FR_OK) 
	{	
		while(1)
		{
	        res = f_readdir(&dir, &fileinfo);                  
	        if (res != FR_OK || fileinfo.fname[0] == 0) 
            {
                break;
            }  
            LOS_CAN_Transmit(LOS_CAN_NUM1, 0x08000001, fileinfo.fname, 8);
		} 
    }	   
    return res;	 
}



